/*
 * Project: Digital Wristwatch
 * Author: Zak Kemble, contact@zakkemble.co.uk
 * Copyright: (C) 2013 by Zak Kemble
 * License: GNU GPL v3 (see License.txt)
 * Web: http://blog.zakkemble.co.uk/diy-digital-wristwatch/
 */

// Button press
// 

#include <avr/io.h>
#include <string.h>
#include <avr/interrupt.h>
#include "common.h"
#include "devices/buttons.h"
#include "devices/buzzer.h"
#include "millis/millis.h"
#include "watchconfig.h"
#include "devices/oled.h"
#include "menu.h"

#define BTN_COUNT	3

#define BTN_DEBOUNCE_TIME	40

#define BTN_PRESS_TONE		TONE_4KHZ
#define BTN_PRESS_TONETIME	80

#define BTN_IS_PRESSED	0x0f
#define BTN_NOT_PRESSED	0x03


#define ENABLE_ADCA()	(ADCA.CTRLA = 0x01)
#define DISABLE_ADCA()	(ADCA.CTRLA = 0x00)

#define START_ADC()		setbit(ADCA.CH1.CTRL, 7)
#define WAIT_CONVERT()		do{ while(!testbit(ADCA.CH1.INTFLAGS,0)); ADCA.CH1.INTFLAGS = 1;}while(0)

typedef struct {
	millis_t pressedTime;
	byte pressed;
	bool funcDone;
	button_f onPress;
//	bool polled;
}s_button;

static s_button buttons[BTN_COUNT];
static bool power_down;

static byte get_key_value(void);
static void processButtons(void);
static void processButton(s_button*, bool);

const uint8_t key_value_map[] = {
	250, 231, 210, 186, 158, 126, 86, 0,
};


void buttons_init()
{
	// ADC
	ADCA.CALL = SP_ReadCalibrationByte(0x20 );
	ADCA.CALH = SP_ReadCalibrationByte(0x21 );

	ADCA.CTRLB = 0x64;			// High current limit, signed mode, no free run, 8 bit
	ADCA.PRESCALER = 0x07;		// Prescaler 512 (62.5kHZ ADC clock)
	ENABLE_ADCA();	// Enable ADC

	ADCA.REFCTRL	  = 0x12;	// REF= VCC/1.6 (3.3V/1.6 = 2.0625V), bandgap enable
	ADCA.CH1.MUXCTRL  = 0x08;	// Channel 1 input: ADC1 pin
	ADCA.CH1.CTRL	  = 0x01;	// Single-ended positive input signal
	PORTA.PIN1CTRL	  = 0x07;  //Digital input buffer disabled

	PORTA.PIN7CTRL	= 0x10;//PIN_KEY_MAIN - pull down, Sense rising edge
	PORTA.INTCTRL  |= 0x01;
	PORTA.INT0MASK |= 0x80;//Key Main at PA7

	power_down = false;
}

void buttons_update()
{
	static millis8_t lastUpdate;

	millis8_t now = millis();
	if((millis8_t)(now - lastUpdate) >= 10)
	{
		lastUpdate = now;
		processButtons();
	}
}

void short_delay(void)
{
	ms_delay(10);
}
void long_delay(void)
{
	ms_delay(500);
}

static byte get_key_value(void)
{
	byte adc0, adc1, pressed = KEY_NONE;

	//do{
		if(testbit(PORTA.IN ,7)) {
			pressed = KEY_MAIN;
		} else	{
			START_ADC();
			WAIT_CONVERT();
			adc0 = ADCA.CH1.RESL;
			if(adc0 <= 250) {
				short_delay();
				START_ADC();
				WAIT_CONVERT();
				adc1 = ADCA.CH1.RESL;
				if(adc1 - adc0 <= 1) {
					for(pressed = 0; pressed < 8; pressed++) {
						if(adc1 >= key_value_map[pressed]) {
							break;
						}
					}
				}
			}
		}
		//if(key != KEY_NONE) {
		//	pressed = key;
			//short_delay();
		//}
	//}while(key != KEY_NONE);
	return pressed;
}

void key_wait_up(void)
{
	do {
		ms_delay(50);
	}while(get_key_value() != KEY_NONE);
}

bool buttons_pwr_down(void)
{
	return power_down;
}

void set_pwr_down(void)
{
	power_down = true;
}

static void processButtons()
{
	static uint8_t long_press;

	byte pressed = get_key_value();

	if(pressed == KEY_MAIN) {
		if(menu_isOpen()) {
			key_wait_up();
			menu_close();
		} else {
			if(long_press++ > 80) {
				power_down = true;
			}
		}
	} else {
		long_press = 0;
	}

	bool isPressed[3];
	isPressed[BTN_UP]		= false;
	isPressed[BTN_SELECT]	= false;
	isPressed[BTN_DOWN]		= false;

	if(pressed == KEY_3WS_UP) {
		isPressed[BTN_DOWN] = true;
	} else if(pressed == KEY_3WS_PUSH) {
		isPressed[BTN_SELECT] = true;
	} else if(pressed == KEY_3WS_DOWN) {
		isPressed[BTN_UP] = true;
	}

	LOOPR(BTN_COUNT, i)
		processButton(&buttons[i], isPressed[i]);
}

static void processButton(s_button* button, bool isPressed)
{
	button->pressed <<= 1;
	if(isPressed)
	{
		button->pressed |= 1;
		if(button->pressed >= BTN_IS_PRESSED)
		{
			button->pressedTime = millis(); // this should only be set once!		

			if(!button->funcDone && button->onPress != NULL && button->onPress())
			{
				button->funcDone = true;
				buzzer_buzz(BTN_PRESS_TONETIME, BTN_PRESS_TONE, VOL_UI);
			}
		}
	}
	else
	{
		button->pressed <<= 1;
		if(button->pressed <= BTN_NOT_PRESSED)
			button->funcDone = false;
	}

}

// Set function to run when button pressed
button_f buttons_setFunc(btn_t btn, button_f func)
{
	button_f old = buttons[btn].onPress;
	buttons[btn].onPress = func;
	return old;
}

bool buttons_isActive()
{
	if(!watchConfig.sleepTimeout)
		return true;

	uint timeout = (watchConfig.sleepTimeout * 5) * 1000;

	LOOPR(BTN_COUNT, i)
	{
		if(millis() - buttons[i].pressedTime < timeout)
			return true;
	}

	return false;
}

// Clear button status
void buttons_clear()
{
	LOOPR(BTN_COUNT, i)
	{
		buttons[i].funcDone		= true;
		buttons[i].pressedTime	= millis();
	}
}

void buttons_sleep(void)
{
	//clrbit( ADCA.REFCTRL, 1);//1V ref
	//DISABLE_ADCA();
	vbat_m_pwr_off();
}
void buttons_wake(void)
{
	vbat_m_pwr_on();
	//ENABLE_ADCA()	;
	//setbit( ADCA.REFCTRL, 1);
}


ISR(PORTA_INT0_vect)
{
	//Use for wake up cpu
}
